package com.usian.admin.service.impl

import com.alibaba.fastjson.JSON
import com.usian.admin.feign.ArticleFeign
import com.usian.admin.feign.WemediaFeign
import com.usian.admin.mapper.AdChannelMapper
import com.usian.admin.mapper.AdSensitiveMapper
import com.usian.admin.service.WemediaNewsAutoScanService
import com.usian.common.aliyun.GreeTextScan
import com.usian.common.aliyun.GreenImageScan
import com.usian.common.fast_dfs.FastDFSClient
import com.usian.model.admin.dtos.NewsAuthDto
import com.usian.model.article.pojos.ApArticle
import com.usian.model.article.pojos.ApArticleConfig
import com.usian.model.article.pojos.ApArticleContent
import com.usian.model.common.dtos.PageResponseResult
import com.usian.model.common.dtos.ResponseResult
import com.usian.model.common.enums.AppHttpCodeEnum
import com.usian.model.media.pojos.WmNews
import com.usian.utils.common.SensitiveWordUtil
import io.seata.spring.annotation.GlobalTransactional
import org.apache.jute.Index
import org.elasticsearch.action.index.IndexRequest
import org.elasticsearch.client.RequestOptions
import org.elasticsearch.client.RestHighLevelClient
import org.jetbrains.annotations.Mutable
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Service
import java.util.*
import javax.xml.crypto.Data

@Service
open class WemediaNewsAutoScanServiceImpl : WemediaNewsAutoScanService {
    @Autowired
    private lateinit var restHighLevelClient: RestHighLevelClient;

    override fun findNews(dto: NewsAuthDto): PageResponseResult = wemediaFeign.findList(dto).apply {
        host = baseUrl
    }

    override fun findOne(id: Int?): ResponseResult<*> {
        if (id == null) ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID)
        return ResponseResult.okResult(wemediaFeign.findWmNewsVo(id)).apply {
            host = baseUrl
        }
    }

    override fun updateStatus(type: Int?, dto: NewsAuthDto): ResponseResult<*> {
        if (type == null || dto == null || dto.id == null || (type != 0 && type != 1)) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID)
        }
        wemediaFeign.findById(dto.id).apply {
            status = if (type == 0) 2 else 4
            reason = if (type == 0) dto.msg else "人工审核通过"
            wemediaFeign.updateWmNews(this)
        }
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS)
    }

    @Autowired
    private lateinit var articleFeign: ArticleFeign

    @Autowired
    private lateinit var greenImageScan: GreenImageScan

    @Autowired
    private lateinit var adChannelMapper: AdChannelMapper

    @Autowired
    private lateinit var greenTextScan: GreeTextScan

    @Autowired
    private lateinit var fastDFSClient: FastDFSClient

    @Value("\${fdfs.url}")
    private lateinit var baseUrl: String

    @Autowired
    private lateinit var sensitiveMapper: AdSensitiveMapper

    @Autowired
    private lateinit var wemediaFeign: WemediaFeign

    @GlobalTransactional
    override fun autoScanByMediaNewsId(id: Long): ResponseResult<*>? {
        //参数校验   文章Id
        if (id == null) return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE)
        //1.根据自媒体人发布的文章Id查询自媒体文章信息   若为空则数据不存在
        var wmNews: WmNews = wemediaFeign.findById(id.toInt())
                ?: return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "该新闻不存在")
        //2.文章状态为4（人工审核通过）直接保存数据和创建索引 ;文章状态为8  发布时间>当前时间 直接保存数据 ;文章状态为1，待审核
        wmNews?.run {
            if (status == 4.toShort() || (status == 8.toShort() && publishTime.time <= System.currentTimeMillis())) saveAppArticle(this)
            if (status == 1.toShort()) {
                var text = StringBuilder()  //即将拼接的所有文本内容
                val imageList: MutableList<String> = mutableListOf() //即将组合的所有图片
                JSON.parseArray(content).forEach {
                    //content图文内容转json数组
                    var parseObject = JSON.parseObject(it.toString()) //content图文内容转jsonObject
                    if (parseObject["type"] == "text") text.append(parseObject["value"]) //获取type为"text"的"value  添加到61行定义的text中
                    else imageList.add(parseObject["value"].toString())//获取type不为"text"（也就是图片）  放入62行定义imageList中
                }
                if (images.isNotBlank()) {//新闻对象中的封面图
                    imageList.addAll(images.split(","))//图片用“，”隔开
                }
                //文本审核    调用工具类进行审核
                greenTextScan.greeTextScan(text.toString())["suggestion"].let {
                    if (it != "pass") {//如果没有通过  为block 或 review 则未通过  返回原因且修改状态为审核失败或人工审核
                        if (it == "block") {
                            reason = "文章内容中有敏感词汇"
                            status = 2
                        }
                        if (it == "review") {
                            reason = "文章内容中有不确定词汇"
                            status = 3
                        }
                        wemediaFeign.updateWmNews(this)////更新对应字段信息到表中   通知前端(或自媒体人 审核未通过)
                        return ResponseResult.okResult(0, "审核未通过")
                    }
                }
                //将要审核的图片下载到byteList里
                var byteList: MutableList<ByteArray> = mutableListOf()
                imageList.forEach {
                    val ti = it.replace(baseUrl, "")
                    var i = ti.indexOf("/")
//                  group1/M00/00/00/wKg6imMWAE6AHXk1AAF8BFXvGT047.jpeg
//                  组名：group1       路径：M00/00/00/wKg6imMWAE6AHXk1AAF8BFXvGT047.jpeg
//                  获取第一个/的位置  第一个“/”之前的为组名  之后的为路径
                    byteList.add(fastDFSClient.download(ti.substring(0, i), ti.substring(i + 1)))//通过组名和路径从fastDFS中下载图片并存到byteList中   (i+1  i为“/”的位置，不要“/” +1从i的下一位算起)
                }
                //图片审核
                greenImageScan.imageScan(byteList)["suggestion"].let {
                    if (it != "pass") {//如果没有通过  为block 或 review 则未通过  返回原因且修改状态为审核失败或人工审核
                        if (it == "block") {
                            reason = "文章图片中有违规"
                            status = 2
                        }
                        if (it == "review") {
                            reason = "文章图片中有不确定元素"
                            status = 3
                        }
                        wemediaFeign.updateWmNews(this)//更新状态信息到表中    通知前端(或自媒体人：审核未通过)
                        return ResponseResult.okResult(0, "审核未通过")
                    }
                }
                //敏感词过滤    1.将敏感词都查出来
                sensitiveMapper.findAllSensitive().let {
                    SensitiveWordUtil.initMap(it)//将敏感词集合生成关键词字典库
                    var matchWords = SensitiveWordUtil.matchWords(text.toString())//获取匹配的关键词和命中次数
                    if (matchWords.isNotEmpty()) {//如果有命中的说明有违规的   修改状态 更新到表中
                        status = 2
                        reason = "内容中包含敏感词"
                        wemediaFeign.updateWmNews(this)
                        return ResponseResult.okResult(0, "审核失败")
                    }
                }
                if (publishTime.time > System.currentTimeMillis()) {//审核通过，但是未到发布时间  修改状态   更新到表中
                    status = 8
                    wemediaFeign.updateWmNews(this)
                    return ResponseResult.okResult(0, "审核通过待发布")
                }
                saveAppArticle(this)//审核通过   则准备更新文章的数据  发布文章
                return ResponseResult.okResult(0, "已发布")
            }
        }
        return null
    }

    private fun saveAppArticle(wmNews: WmNews) {
        val apArticle = ApArticle().run {
            //   将相应字段信息同步信息到文章信息表，存储已发布的文章
            title = wmNews.title  //标题
            layout = wmNews.type  //文章布局
            images = wmNews.images  //文章图片
            publishTime = Date()    //发布时间
            var wmUser = wemediaFeign.findWmUserById(wmNews.userId.toLong())//通过自媒体用户Id找到他
            if (wmUser != null) {
                var author = articleFeign.selectAuthorByName(wmUser.name)//根据自媒体用户信息查询到作者信息
                authorId = author.id.toLong()   //作者Id
                authorName = author.name           //作者名字
                //根据文章中的频道Id找到频道信息
                adChannelMapper.selectById(wmNews.channelId).let {
                    channelId = it.id
                    channelName = it.name
                }
            }
            //同步更新   保存文章的列表信息
            articleFeign.saveArticle(this)
        }
        //更新文章的配置信息到APP已发布文章配置表
        articleFeign.saveArticleConfig(ApArticleConfig().apply {
            articleId = apArticle.id
            isForward = true                    //是否转发
            isDelete = false                    //是否已删除
            isDown = true                       //是否下架
            isComment = true                    //是否可评论
        })
        //更新内容到APP已发布文章内容表
        articleFeign.saveArticleContent(ApArticleContent().apply {
            articleId = apArticle.id
            content = wmNews.content
        })
        //如果以上都通过   则修改状态为9 返回信息为：审核通过
        wmNews.status = 9
        wmNews.reason = "审核通过"
        wemediaFeign.updateWmNews(wmNews) //同步更新到自媒体图文内容(新闻表wm_news)信息表

        val map: MutableMap<String, Any> = mutableMapOf()
        map["id"] = apArticle.id.toString()
        map["publishTime"] = apArticle.publishTime
        map["layout"] = apArticle.layout
        map["images"] = apArticle.images
        map["authorId"] = apArticle.authorId
        map["title"] = apArticle.title
        map["content"] = wmNews.content
        restHighLevelClient.index(IndexRequest("app_info_article").apply {
            source(map)
            id(apArticle.id.toString())
        }, RequestOptions.DEFAULT)
    }
}